package com.payment.service.impl;

import cn.hutool.core.util.URLUtil;
import com.alipay.v3.ApiException;
import com.alipay.v3.model.*;
import com.alipay.v3.util.AlipaySignature;
import com.aliyun.pojo.pay.AliyunPay;
import com.aliyun.pojo.pay.AliyunPayRefundParam;
import com.aliyun.properties.AliyunProperties;
import com.aliyun.service.impl.AliyunPayService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.payment.domain.pojo.PaymentRecord;
import com.payment.domain.vo.ZfbCallbackVo;
import com.payment.enums.PaymentStatus;
import com.payment.service.IPaymentRecordService;
import com.payment.service.IPaymentService;
import com.payment.service.PaymentServiceFactory;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

@Service(value = "zfb-payment-service")
@Slf4j
public class ZfbPaymentServiceImpl implements IPaymentService{

    @Resource
    AliyunPayService aliyunPayService;

    @Resource
    AliyunProperties aliyunProperties;

    @Resource
    IPaymentRecordService iPaymentRecordService;

    @Override
    public String payment(String out_trade_no, BigDecimal total_amount, String subject, GoodsDetail[] goodsDetails) {
        return aliyunPayService.payment(out_trade_no, total_amount, subject,goodsDetails);
    }

    /**
     * 在通知返回参数列表中，除去 sign、sign_type 两个参数外，凡是通知返回回来的参数皆是待验签的参数
     *
     * @param request
     * @return
     */
    public ZfbCallbackVo callback(HttpServletRequest request, HttpServletResponse response) throws IOException, ApiException {
        // 1：得到待验签的参数
        Map<String, String[]> requestParameterMap = request.getParameterMap();
        Map<String, String> paramsMap = new HashMap<>();
        // 2：待验签的参数进行 url_decode
        for (Map.Entry<String, String[]> entry : requestParameterMap.entrySet()) {
            String key = entry.getKey();
            StringBuilder param = new StringBuilder();
            for (String str : entry.getValue()) {
                param.append(str).append(",");
            }
            if (param.length() > 0) {
                param.deleteCharAt(param.length() - 1); // 删除末尾逗号
            }
            // 除去 sign、sign_type  将剩下参数进行 url_decode
            if ("sign".equals(key) || "sign_type".equals(key)) {
                paramsMap.put(key, param.toString());
            } else {
                paramsMap.put(key, URLUtil.decode(param.toString()));
            }
        }
        // 3：将签名参数（sign）使用 base64 解码为字节码串。
        // 4：使用 RSA 的验签方法，通过签名字符串、签名参数（经过 base64 解码）及支付宝公钥验证签名。
        AliyunPay aliyunPay = aliyunProperties.getPay();
        boolean  signVerified = AlipaySignature.rsaCheckV1(paramsMap, aliyunPay.getPublic_key(), "UTF-8", "RSA2");  //调用SDK验证签名
        if (signVerified) {
            // 5：验签成功，进行商家自身验证
            String outTradeNo = paramsMap.get("out_trade_no");  // 订单号
            String tradeNo = paramsMap.get("trade_no");  // 支付宝交易号
            String totalAmount = paramsMap.get("total_amount");  // 订单金额
            String appId = paramsMap.get("app_id");  // 商家id
            String sellerId = paramsMap.get("seller_id");  // 商家支付宝id
            String buyerOpenId = paramsMap.get("buyer_open_id");  // 买家支付宝用户号
            if (!aliyunPay.getApp_id().equals(appId)) {
                log.error("支付宝异步回调：商家id不一致 订单号：{}",outTradeNo);
                response.getWriter().write("failure");  // 告诉支付宝处理失败
                return null;
            }
            if (!iPaymentRecordService.exists(new LambdaQueryWrapper<PaymentRecord>()
                    .eq(PaymentRecord::getOrderNo, outTradeNo)
                    .eq(PaymentRecord::getPaymentAmount, totalAmount))) {
                log.error("支付宝异步回调：订单不存在 订单号：{}",outTradeNo);
                response.getWriter().write("failure");  // 告诉支付宝处理失败
                return null;
            }
            if (!aliyunPay.getSeller_id().equals(sellerId)) {
                log.error("支付宝异步回调：商家支付宝id不一致 订单号：{}",outTradeNo);
                response.getWriter().write("failure");  // 告诉支付宝处理失败
                return null;
            }
            // 业务幂等校验 判断当前订单是否已经支付成功
            if (iPaymentRecordService.exists(new LambdaQueryWrapper<PaymentRecord>()
                    .eq(PaymentRecord::getOrderNo, outTradeNo)
                    .eq(PaymentRecord::getPaymentStatus, PaymentStatus.SUCCESS.getCode()))) {
                log.debug("支付宝异步回调：重复通知 订单：{} 已经支付成功", outTradeNo);
                response.getWriter().write("success");
                return null;
            }
            log.info("支付宝异步回调：订单：{} 支付成功", outTradeNo);
            response.getWriter().write("success");
            return new ZfbCallbackVo(outTradeNo,tradeNo,buyerOpenId);
        } else {
            log.error("支付宝异步回调：验签失败");
            response.getWriter().write("failure");  // 告诉支付宝处理失败
            return null;
        }
    }

    @Override
    public String cancel(String out_trade_no,String trade_no) {
        AlipayTradeCloseResponseModel responseModel = aliyunPayService.close(out_trade_no, trade_no);
        return responseModel == null ? null : responseModel.getTradeNo();
    }
    @Override
    public AlipayTradeRefundResponseModel refund(AliyunPayRefundParam aliyunPayRefundParam) {
        return aliyunPayService.refund(aliyunPayRefundParam);
    }
    @Override
    public String queryTradeStatus(String out_trade_no,String trade_no) {
        AlipayTradeQueryResponseModel responseModel = queryTrade(out_trade_no, trade_no);
        return responseModel == null ? null : responseModel.getTradeStatus();
    }
    public String queryTradeNo(String outTradeNo) {
        AlipayTradeQueryResponseModel responseModel = queryTrade(outTradeNo, null);
        return responseModel == null ? null : responseModel.getTradeNo();
    }

    public AlipayTradeQueryResponseModel queryTrade(String outTradeNo, String tradeNo) {
        return aliyunPayService.queryTrade(outTradeNo, tradeNo);
    }

    public AlipayTradeFastpayRefundQueryResponseModel queryRefund(String outRequestNo, String outTradeNo, String tradeNo) {
        return aliyunPayService.queryRefund(outRequestNo, outTradeNo, tradeNo);
    }
}
